Hello world!

#include "epiworld.hpp"

int main() {
1    epiworld::epimodels::ModelSIR<> model(
        "Flu", // Name
        .01,   // Initial infected
        .2,    // Transmission rate
        .14    // Recovery rate
        );

2    model.agents_smallworld(
        100000, // Population size
        10,     // Number of contacts
        false,  // Directed = false
        0.01    // Rewiring probability
        );

    // Running and printing!
3    model.run(100, 771);
4    model.print();

    return 0;
}
1
Create a SIR model.
2
Create a small-world network.
3
Run the model for 100 days.
4
Print the results.
> ./hello-world.o
_________________________________________________________________________
Running the model...
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| done.
 done.
________________________________________________________________________________
________________________________________________________________________________
SIMULATION STUDY

Name of the model   : Susceptible-Infected-Recovered (SIR)
Population size     : 100000
Agents' data        : (none)
Number of entities  : 0
Days (duration)     : 100 (of 100)
Number of viruses   : 1
Last run elapsed t  : 116.00ms
Last run speed      : 85.53 million agents x day / second
Rewiring            : off

Global events:
 (none)

Virus(es):
 - covid

Tool(s):
 (none)

Model parameters:
 - Recovery rate     : 0.1400
 - Transmission rate : 0.2000

Distribution of the population at time 100:
  - (0) Susceptible :  99000 -> 495
  - (1) Infected    :   1000 -> 213
  - (2) Recovered   :      0 -> 99292

Transition Probabilities:
 - Susceptible  0.95  0.05  0.00
 - Infected     0.00  0.86  0.14
 - Recovered    0.00  0.00  1.00

Full code available here.

About the software

A general framework for epidemiological agent-based models:

Lightweight

  • Built on the C++ standard library.
  • Easy to port to other languages (R, Python).

A Framework

  • Highly modular.
  • User-defined states and update dynamics.

Fast

  • Out-of-the-box parallelism.
  • Up to 100 million agents-day per second.

Complex

  • Multi-virus.
  • Evolving virus.
  • Heterogeneous populations.

About the software: research

We built epiworld to support our research in epidemiological agent-based models:

Meyer, Derek and Vega Yon, George (2023). epiworldR: Fast Agent-Based Epi Models. Journal of Open Source Software, 8(90), 5781, https://doi.org/10.21105/joss.05781

  • Core library: epiworld (C++) codecov codecov 84% 84% .

  • Existing packages: epiworldR (on CRAN), epiworldRShiny (on CRAN), epiworldpy, and epiworldweb (the last two under development).

  • Research projects involving epiworld:

    1. Calibration of ABMs via machine learning (large number of simulations).
    2. Forecasting models with mechanistic machine learning (also large number of simulations).
    3. Reproductive number estimation methods applied to ABMs.
    4. How network properties affect epidemiological statistics.
    5. Theoretical distribution of Rt and Generation Time in ABMs.

Example

Demo: SEIR model

  • SEIR model.

  • Population of 200 K agents in a connected graph.

  • Two initial viruses: COVID-19 and the Flu.

  • Flu has 0.001 probability of mutating. These change the transmission rate.

  • Policy: 30% of vaccinated agents.

  • Non-pharmaceutical intervention [NPI] : full isolation trigerred when the daily cases are above 1,000. Cools downs when below 100.

Running the model...
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| done.
 done.
________________________________________________________________________________
________________________________________________________________________________
SIMULATION STUDY

Name of the model   : Susceptible-Exposed-Infected-Removed (SEIR) (connected)
Population size     : 200000
Agents' data        : (none)
Number of entities  : 0
Days (duration)     : 180 (of 180)
Number of viruses   : 205
Last run elapsed t  : 1.00s
Last run speed      : 33.36 million agents x day / second
Rewiring            : off

Global events:
 - Update infected individuals (runs daily)
 - Full isolate (runs daily)

Virus(es):
 - Covid-19
 - Flu
 ...and 203 more variants...

Tool(s):
 - Vaccine

Model parameters:
 - Avg. Incubation days : 7.0000
 - Contact rate         : 0.3000
 - Prob. Recovery       : 0.1429
 - Prob. Transmission   : 0.3000

Distribution of the population at time 180:
  - (0) Susceptible : 199960 -> 128884
  - (1) Exposed     :     40 -> 1754
  - (2) Infected    :      0 -> 2261
  - (3) Recovered   :      0 -> 67101

Transition Probabilities:
 - Susceptible  1.00  0.00  0.00  0.00
 - Exposed      0.00  0.84  0.16  0.00
 - Infected     0.00  0.00  0.80  0.20
 - Recovered    0.00  0.00  0.00  1.00

Full code available here.

Demo: Mutating virus

// Creating the model
1Virus<> flu("Flu");
2flu.set_incubation(5.0);
flu.set_prob_infecting(0.2);
flu.set_prob_recovery(1.0/7.0);

// Adding mutation
3flu.set_mutation(flumutates);

// How will it be distributed 
4flu.set_distribution(
  distribute_virus_randomly<>(20, false)
  ); 

// Adding the virus to the model
5flu.set_state(1, 3);
model.add_virus(flu);
1
Create a new virus.
2
Define the virus parameters.
3
Define a mutation function.
4
Define how the virus will be distributed.
5
Add the virus to the model.

Demo: Mutating virus

Phylogeny of the flu variants. Each node represents a flu variant colored and sized by the transmission rate (larger+more orange = more transmissible).

Demo: Non-pharma intervention

1EPI_NEW_GLOBALFUN(full_isolation, int)
{
        
    // Getting new exposed from the model
    m->get_db().get_today_transition_matrix(tmatrix);
    int new_exposed = tmatrix[4]; 
    
    // Applying the policy
    if (new_exposed > 1000)
        m->set_param("Contact rate",  0.3);
    if (new_exposed < 100)
        m->set_param("Contact rate",  10);

}

2model.add_globalevent(full_isolation, "Full isolate", -99);
1
Design the intervention.
2
Add the intervention to the model (-99 = runs daily).

Demo: Non-pharma intervention

Daily incidence of the flu variants. Each line represents a flu variant colored by the transmission rate. The NPI is triggered when the daily cases are above 1,000 and cools down when below 100.

Demo: Speed-wise

  • This experiment (200 K agents for 180 days) took 1 second to run. As a reference, here is a comparison with other tools (different model):

Simulated a network SIR with 50 K agents:

  • Covasim (Python): ~ 1 second (although the model is more complex, SIRd).
  • Epiworld is 3x faster than igraph, 14x faster than AnyLogic, and 28x faster than ABM.

Demo: Full code

#include "epiworld.hpp"

using namespace epiworld;

// Some constants
const static double p_mutate = 0.001;
const static int max_int = std::numeric_limits<int>::max();

EPI_NEW_MUTFUN(flumutates, int)
{

    if (p_mutate > m->runif())
    {
        // Creating new random sequence and updating
        // transmission probability
        double new_pinfect = m->runif() * 0.7;
        v.set_sequence(static_cast<int>(new_pinfect * max_int));
        v.set_prob_infecting(new_pinfect);
        v.set_name("flu-variant-" + std::to_string(new_pinfect));

        return true;
    }

    return false;

}

std::vector<int> tmatrix;
EPI_NEW_GLOBALFUN(full_isolation, int)
{
        
    m->get_db().get_today_transition_matrix(tmatrix);
    int new_exposed = tmatrix[4]; 
    
    if (new_exposed > 1000)
        m->set_param("Contact rate",  0.3);
    if (new_exposed < 100)
        m->set_param("Contact rate",  10);

};

int main() {

    // Initializing one of the existing models.
    // In this case, network SEIR.
    epimodels::ModelSEIRCONN<> model(
        "Covid-19",
        2e5,    // Population size
        0.0001, // ~20 cases
        10,      // Contact rate
        0.3,    // Transmission rate
        7.0,    // Mean incubation
        1.0/7.0 // Recovery rate
    );

    // VIRUS DESIGN --------------------------------
    Virus<> flu("Flu");
    flu.set_incubation(5.0);
    flu.set_prob_infecting(0.2);
    flu.set_prob_recovery(1.0/7.0);

    // Adding mutation
    flu.set_mutation(flumutates);

    // How will it be distributed
    flu.set_distribution(
        distribute_virus_randomly<>(20, false)
        );
    
    // Adding virus to the model
    flu.set_state(1, 3);
    model.add_virus(flu);

    // Tool design ----------------------------------
    Tool<> vaccine("Vaccine");
    vaccine.set_transmission_reduction(0.3);
    vaccine.set_recovery_enhancer(0.9);
    vaccine.set_distribution(
        distribute_tool_randomly<>(0.3, true)
    );

    model.add_tool(vaccine);

    // Designing intervention: isolation --------------------
    model.add_globalevent(full_isolation, "Full isolate");

    // Running the model
    model.run(180, 221);
    model.print();

    // Saving the data
    model.write_data(
        "res/virus_info.tsv",
        "res/virus_hist.tsv",
        "res/tool_info.tsv",
        "res/tool_hist.tsv",
        "res/total_hist.tsv",
        "res/transmissions.tsv",
        "res/transitions.tsv",
        "res/repnum.tsv",
        "res/gentime.tsv"
    );

    return 0;

}

Final thoughts

Final thoughts

  • epiworld is a fast C++ library for epidemiological agent-based models.

  • Actively developed and featured in various Epi ABM studies.

  • User-friendly versions exist for R and Python.

  • It’s a framework: you can define your own states and update dynamics.

  • You can get it at https://github.com/UofUEpiBio/epiworld.


Thanks!

epiworld: “A fast multi-language library for epi ABMs”

George G. Vega Yon, Ph.D.

https://ggvy.cl